import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue;

public class DispatchModule {
}

class AskForThread implements Runnable {
    Map<String, FileHoldingListPublic> file_hold_list_public_map;
    Map<String, CtrlSendQueue> CtrlSendQueue_map;
    BlockingQueue<AskFor_ResponseQueue_info> askfor_response_queue;

    @Override
    public void run() {
        file_hold_list_public_map = FileHoldingListPublicMap.getMap();
        CtrlSendQueue_map = ControlConnectionModule.getInstance().SendQueue_map;
        askfor_response_queue = AskFor_ResponseQueue.getQueue();
        while (true) {
            //获取到当前正在接收哪个文件
            String now_receiving_file_md5 = FileHoldingListPublicMap.getNow_receiving_file_md5();
            if (now_receiving_file_md5 == null) {//等于null表示当前不在接收任何文件,跳过循环
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                continue;
            }
            //获取到这个文件的"全网文件持有表",以及这个文件的"自己的文件片持有表"
            FileHoldingListPublic FHL_P = FileHoldingListPublicMap.getMap().get(now_receiving_file_md5);
            FileHoldingListSelf FHL_S = FileHoldingListSelfMap.getMap().get(now_receiving_file_md5);

            //遍历这个文件持有表的所有文件片(只要FHL_P内不是所有文件片都接收到了,就要继续循环)(注意,是FHL_P,而不是FHL_S)
            //这里做出假设, 结点 永不掉线.........(实际上是是在没时间写了,在设计上是留了结点掉线的余量的)
            while (true) {
                //判断是否全接收到
                //获取FHL_P的文件片列表
                FCL_P_item[] file_chunk_list = FHL_P.getFile_chunk_list();
                boolean mark_end = true;
                for (int i = 0; i < file_chunk_list.length; i++) {
                    if (file_chunk_list[i].isIs_response() == false) {
                        mark_end = false;
                        break;
                    }
                }
                if (mark_end) {//表示"所有文件片都被响应了",可以结束"索要"循环
                    break;
                }

                //开始遍历所有文件片进行索要(此处为 循环 + 自动机!!!)
                for (int i = 0; i < file_chunk_list.length; i++) {
                    //当有一个文件片未被接收到 -> 进入此文件片的自动机
                    if (file_chunk_list[i].isIs_response() == false) {
                        //遍历这个文件片的所有持有者
                        //获取这个文件片的持有者表
                        CopyOnWriteArraySet<String> holder_set = file_chunk_list[i].getHolder_set();
                        for (String holder_ip : holder_set) {//不知道这样会不会有线程安全问题,比如从set内删除元素
                            //向持有者发送"索要文件片file_chunk_list[i]"的[索要报文]
                            CtrlSendQueue holder_ctrl_send_queue= CtrlSendQueue_map.get(holder_ip);
                            //向这个"持有者"的"控制报文发送队列"里塞入[索要报文] (i就是文件片序列号)
                            holder_ctrl_send_queue.put(MessageEncapsulationUtils.MessageToChunk(MessageEncapsulationUtils.AskForMessage_pack(now_receiving_file_md5, i)));
                            //等待发送给它的那个客户端响应(这个函数是阻塞函数,会等待至[索要响应报文]返回)
                            try {
                                AskFor_ResponseQueue_info AFR_info = askfor_response_queue.take();
                                if(AFR_info.is_agree == true){//如果这个客户端同意了,就修改file_chunk_list的is_response字段
                                    file_chunk_list[i].setIs_response(true);
                                    break;//有一个客户端同意就可以跳出循环了
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

            }
        }
    }
}

//"文件片索要线程" 响应接收队列 的存储元素 [索要响应报文]信息
class AskFor_ResponseQueue_info {
    String file_md5;//索取的文件md5值
    int serial_num;//索取的文件片序列号
    String ip;//响应的客户端ip
    boolean is_agree;//资源持有方是否愿意发送给你
}
//存放[索要响应报文]的queue
class AskFor_ResponseQueue {
    private static BlockingQueue<AskFor_ResponseQueue_info> askfor_response_queue;
    private static final AskFor_ResponseQueue INSTANCE = new AskFor_ResponseQueue();

    AskFor_ResponseQueue() {
        System.out.println("AskFor_ResponseQueue\"文件片索要线程\"响应接收队列 已创建");
        askfor_response_queue = new LinkedBlockingQueue<>();
    }

    public static BlockingQueue<AskFor_ResponseQueue_info> getQueue() {
        return askfor_response_queue;
    }
}


class ResourceHoldingThread {

}

class ResourceHolding_ResponseQueue_info {
    String file_md5;//索取的文件md5值
    int serial_num;//索取的文件片序列号
    String ip;//响应的客户端ip
}